<?
/**
 * Classe Generateur
 * Permet de créer une classe de gestion d'une table de BD
 * @author Charles-Alexandre Monette
 * @date 2007/06/28
 */
 


class Generateur {

	var $table;
	var $nom;
	var $champs = array();
	var $classe;
	var $pk;
	var $connexion;
	
	/**
	 * Constructeur
	 */
	function Generateur( $nom = "", $table = "" ) {
		$this->nom = $nom;
		$this->table = $table;
	}
	
	/**
	 * Fonction qui permet de changer la table ciblée
	 * @param $table String
	 */
	function setTable( $table ) {
		$this->table = $table;
		$this->_getChamps();
	}
	
	// ajouté par Yann
	/**
	 * Fonction qui établi les paramètres de connexion
	 * @param $host string
	 * @param $db string
	 * @param $user string
	 * @param $psw string
	 */
	 function setBD( $host, $db, $user, $psw ) {
		$this->connexion = mysql_connect( $host, $user, $psw ) or die( mysql_error() );
		mysql_select_db( $db, $this->connexion );
	 }
	 
	/**
	 * Fonction qui permet de changer le nom de la classe à créer
	 * @param $nom String
	 */
	function setNom( $nom ) {
		$this->nom = $nom;
	}
	
	/**
	 * Fonction qui lit la base de données et extrait la structure de table
	 */
	function _getChamps() {
		if ( !empty( $this->table ) ) {
			unset( $this->champs );

			// Extraction des champs de la table spécifiée
			$reqChamps = "SHOW COLUMNS FROM " . mysql_escape_string( $this->table );
			$resChamps = mysql_query( $reqChamps, $this->connexion ) or die ( "Informations incorrectes" );
			
			while ( $champ = mysql_fetch_assoc( $resChamps ) ) {
				$i = count( $this->champs );
				$this->champs[ $i ][ 'champ' ] = $champ[ 'Field' ];
				$this->champs[ $i ][ 'type' ] = $this->_verifType( $champ[ 'Type' ] );
				$this->champs[ $i ][ 'cle' ] = $champ[ 'Key' ];
				$this->champs[ $i ][ 'extra' ] = $champ[ 'Extra' ];
			}
			
		} else {
			$this->_erreur( 'Le champ "table" est vide!' );
		}
	}
	
	/**
	 * Fonction qui transforme les types MySQL en types PHP
	 * @param $type String type MySQL en entrée
	 * @return String type PHP en sortie
	 */
	function _verifType( $type ) {
		if ( strpos( $type, 'int' ) !== false ) {
			$type = 'int';
		} else if ( strpos( $type, 'float' ) !== false ) {
			$type = 'float';
		} else if ( strpos( $type, 'char' ) !== false ) {
			$type = 'String';
		} else {
			$type = 'mixed';
		}
		
		return $type;
	}
	
	/**
	 * Fonction créant l'affichage de la classe
	 */
	function creer() {
		$this->_getChamps();
		$this->pk = $this->trouvePK();
		// Commentaires de la classe
		$retour = '<? ' . " \n ";
		$retour  .= "/** \n";
		$retour  .= "* @generator Le Classificateur 2.01 beta " . "\n";
		$retour  .= "* @author Yann Boisclair-Roy ". "\n";
		$retour  .= "* @date " . date( "Y/m/d" ). "\n";
		$retour  .= "* @desc Classe qui contrôle les données de la table " . $this->table . "\n";
		$retour  .= "*/ ". " \n \n ";
		
		// Début de la classe									   
		$retour .= "class " . $this->nom . " {\n\n";		   
		
		// Variables de classe
		$retour .= " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Flag qui détermine si la recherche devra se faire avec des LIKE \'%%\' ou des " = "' . "\n";
		$retour .= " \t" . '* @var boolean' . "\n";
		$retour .= " \t" . '*/' . "\n";
		$retour .= " \t" . 'var $rechercheExact = true;' . " \n \n";
		
		$retour .= " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Objet de connexion à la base de données' . "\n";
		$retour .= " \t" . '* @var Bd' . "\n";
		$retour .= " \t" . '*/' . "\n";
		$retour .= " \t" . 'var $oBd;' . " \n";
		
		$retour .= " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Variable qui contient un bout de SQL qui déterminera l\'ordre selon les voeux de l\'usager' . "\n";
		$retour .= " \t" . '* @var string' . "\n";
		$retour .= " \t" . '*/' . "\n";
		$retour .= " \t" . 'var $ordre;' . " \n";
		
		$retour .= " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Variable qui contient un bout de SQL qui déterminera la limite selon les voeux de l\'usager' . "\n";
		$retour .= " \t" . '* @var String' . "\n";
		$retour .= " \t" . '*/' . "\n";
		$retour .= " \t" . 'var $limite;' . " \n";
		
		$retour .= " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Variable qui contient un Array des résultats provenant de la requête SQL par GetInfos' . "\n";
		$retour .= " \t" . '* @var Array' . "\n";
		$retour .= " \t" . '*/' . "\n";
		$retour .= " \t" . 'var $resultat;' . " \n";
		
		for( $i = 0; $i < count( $this->champs ); $i++ ) {
			$retour .= " \t" . '/**' . "\n";
			$retour .= " \t" . '* @desc Variables équivalente au champs ' . $this->champs[ $i ][ 'champ' ] . ' de la table ' . $this->table . "\n";
			$retour .= " \t" . '* @var ' . $this->champs[ $i ][ 'type' ] . "\n";
			$retour .= " \t" . '*/' . "\n";
			$retour .= " \t " . 'var $' . $this->champs[ $i ][ 'champ' ] . ';' . "\n \n";
		}
		$retour .= "\n";
		
		$retour .= $this->faitConstructeur();
		
		// Accesseurs et mutateurs
		for( $i = 0; $i < count( $this->champs ); $i++ ) {
			$retour .= $this->creerMutateur( $this->champs[ $i ][ 'champ' ], $this->champs[ $i ][ 'type' ], 1 );
			$retour .= $this->creerAccesseur( $this->champs[ $i ][ 'champ' ], $this->champs[ $i ][ 'type' ], 1 );
		}
		$retour .= $this->faitSetLimite();
		$retour .= $this->faitSetOrdre();    
		$retour .= $this->faitGetResultats(); 
		$retour .= $this->faitSauvegarde();  // fait l'AJOUT ET l'UPDATE
		$retour .= $this->faitGetInfo();
		$retour .= $this->faitDelete();
		$retour .= $this->faitRechercheExact();
		$retour .= $this->faitCleanup();
		
		// Fin de la classe
		$retour .= "}\n";
		$retour .= '?>';
		return $retour;
	}
	
	
	/**
	 * Fonction permettant d'écrire un mutateur
	 * @param $variable String Nom de la variable en entrée
	 * @param $type String Type de variable
	 * @param $tabulation int Nombre de tabulations à imprimer en sortie
	 * @return String
	 */
	function creerMutateur( $variable, $type, $tabulation = 0 ) {
		/* Ajout des commentaires de la fonction */
		$retour = " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Fonction mutatrice du champ ' . $variable . "\n";
		$retour .= " \t" . '* @access public' . "\n";
		$retour .= " \t" . '* @param ' . $type . $variable . "\n";
		$retour .= " \t" . '*/' . "\n";
		
		/* création de la fonctione */
		$retour .= "\t" . "function set" . ucwords( $variable ) . " ( \$" . $variable . " ) {\n";		
		$retour .= "\t\t" . "\$this->" . $variable . " = ";
		if ( $type == 'int' ) {
			$retour .= "intval( \$" . $variable . " )";
		} else {
			$retour .= "addslashes( \$" . $variable . " ) ";
		}
		$retour .= ";\n";
		$retour .= "\t" . "}\n\n\n";
		
		return $retour;
	}
	
	/**
	 * Fonction permettant d'écrire un accesseur
	 * @param $variable String Nom de la variable en entrée
	 * @param $type String Type de variable
	 * @param $tabulation int Nombre de tabulations à imprimer en sortie
	 * @return String
	 */
	function creerAccesseur( $variable, $type, $tabulation = 0 ) {
		/* Ajout des commentaires de la fonction */
		$retour = " \t" . '/**' . "\n";
		$retour .= " \t" . '* @desc Fonction accesseur du champ ' . $variable . "\n";
		$retour .= " \t" . '* @access public' . "\n";
		$retour .= " \t" . '* @return ' . $type . "\n";
		$retour .= " \t" . '*/' . "\n";
		
		/* création de la fonctione */
		$retour .= $tabulations . "\t function get" . ucwords( $variable ) . ' ()' . "{\n";	
		$retour .= $tabulations . "\t \t" . ' return stripslashes( ' . $variable . ');' . "\n";
		$retour .= $tabulations . "\t}\n\n\n";
		
		return $retour;
	}

	// fait la fonction de l'ajout dans ld BD
	function faitSauvegarde() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction d\'ajout et de mise à jour des données.' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @return int' . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		$txt .=  "\t function sauvegarde() { \n ";
			$txt .= " \t\t " . 'if( empty( $this->' . $this->pk . ' ) ) {' . " \n";
			$txt .= " \t\t\t " . '$req = "INSERT INTO ' . $this->table . " ( ";
			for( $i = 0; $i < count( $this->champs ); $i++ ) {
				// si la PK s'inscrémente automatiquement, on ne l'inclu pas dans la requête
				if( $this->champs[ $i ][ 'extra' ] != 'auto_increment' ) {
					$txt .= $this->champs[ $i ][ 'champ' ];
					if( $i !=  count( $this->champs ) -1 ) {
						$txt .=  ", ";
					}
					else {
						$txt .=  " \t) ";
					}
				}
			}
			$txt .=  " VALUES  ( ";
			for( $i = 0; $i < count( $this->champs ); $i++ ) {
				if( $this->champs[ $i ][ 'extra' ] != 'auto_increment' ) {
					if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
						$txt .= " '";
					}
					$txt .=  '" . $this->' . $this->champs[ $i ][ 'champ' ] . ' . "';
					if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
						$txt .= "' ";
					}
					if( $i !=  count( $this->champs ) -1 ) {
						$txt .=  ", ";
					}
				}
			}
			$txt .= ") ON DUPLICATE KEY UPDATE ";
			for( $i = 0; $i < count( $this->champs ); $i++ ) {
				if( $this->champs[ $i ][ 'extra' ] != 'auto_increment' ) {         
					$txt .= $this->champs[ $i ][ 'champ' ] . ' = ' ;
					if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
						$txt .= " '";
					}
					$txt .= '" . $this->' . $this->champs[ $i ][ 'champ' ] . ' . "';
					if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
						$txt .= "' ";
					}
					if( $i != count( $this->champs ) -1 ) {
						$txt .= ", ";
					}
				}
			}
			$txt .= "\"; \n ";
			$txt .=  " \t\t\t " . '$this->oBd->query( $req );' . "\n";
			$txt .=  " \t\t\t " . '$no = $this->oBd->getId(); ' . "\n";
			$txt .=  " \t\t\t " . '$this->' . $this->pk . ' = $no; ' . "\n";
			$txt .=  " \t\t " . '} else { ' . "\n";	
			$txt .= " \t\t\t " . '$req = "UPDATE ' . $this->table . " SET ";
			for( $i = 0; $i < count( $this->champs ); $i++ ) {
				$txt .= $this->champs[ $i ][ 'champ' ] . ' = ' ;
				if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
					$txt .= " '";
				}
				$txt .= '" . $this->' . $this->champs[ $i ][ 'champ' ] . ' . "';
				if( $this->champs[ $i ][ 'type' ] != 'int' && $this->champs[ $i ][ 'type' ] != 'float' ) {
					$txt .= "' ";
				}
				if( $i != count( $this->champs ) -1 ) {
					$txt .= ", ";
				}
			}
			$txt .= ' WHERE ' . $this->pk . ' = " . $this->' . $this->pk . ';' . "\n";
			$txt .=  " \t\t\t " . '$this->oBd->query( $req );' . "\n";
			$txt .=  " \t\t\t " . '$no = $this->' . $this->pk . ';' . "\n";
			$txt .=  " \t\t " . '}' . "\n";	
			
 			$txt .=  " \t\t " . 'return $no;  ' . "\n";	
		$txt .=  " \t }  \n  \n ";
		
		return $txt;
	}
	
	// fonction qui crée la méthode de de suppression de données
	function faitDelete() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction de suppression des données.' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		$txt .= " \t" .'function delete() {' . "\n";
		$txt .= " \t\t " .'$req = "DELETE FROM ' . $this->table . ' WHERE ' ;
		$txt .= $this->getPK() . ' = " . $this->' . $this->getPK();
		$txt .= "; \n ";
		$txt .= " \t\t " .'$this->oBd->query( $req );' . "\n";
		$txt .= " \t " ."} \n\n";
		return $txt;
	}
	
	// trouve le champs avec la clé primaire
	function trouvePK() {
		$var = $this->champs[ 0 ][ 'champ' ];
		for( $z = 0; $z < count( $this->champs ); $z++ ) {
			if( $this->champs[ $z ][ 'cle' ] == 'PRI' ) {
				$var =  $this->champs[ $z ][ 'champ' ];
			}
		}
		return $var;
	}
	
	// retourne le champs de la clé primaire
	function getPK() {
		return $this->pk;
	}
		 
	// fonction qui crée le constructeur de la classe
	function faitConstructeur() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Constructeur de la class ' . $this->table . '. Si à l\'instenciation de la classe on lui donne un numéro de clé primaire, ' . "\n";
		$txt .= " \t" . '*  celle-ci instenciera la class avec toutes les infos dans la table ' . $this->table . ' concernant cette clé primaire.' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @param	Bd	oBd' . "\n";
		$txt .= " \t" . '* @param ' . $this->champs[ 0 ][ 'type' ] . ' ' . $this->champs[ 0 ][ 'champ' ]  . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		/* Création du contructeur */
		$txt .= " \t function " . $this->nom . ' ( $oBd, $' . $this->champs[ 0 ][ 'champ' ] . " = 0 ) { \n" ;
			$txt .= " \t \t " . '$this->oBd = $oBd;' . " \n ";
			$txt .= " \t \t " . 'if( $' . $this->champs[ 0 ][ 'champ' ] . ' > 0 ) { ' . " \n ";
			$txt .= " \t \t \t " . '$this->' . $this->pk . ' = $' . $this->champs[ 0 ][ 'champ' ] . ';' . " \n ";
			$txt .= " \t \t \t " .  '$this->getInfos();' . " \n ";
			$txt .= " \t \t " ."} \n";
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;
	}
	
	function faitSetOrdre() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction mutatrice de l\'ordre' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @param string ordre' . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		$txt .= " \t " . 'function setOrdre( $ordre ) { ' . " \n" ;
			$txt .= " \t \t " . '$this->ordre =  $ordre; ' . " \n";
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;
	}
	
	function faitGetResultats() {
				/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction mutatrice de resultats' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @return Array Resultats' . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		$txt .= " \t " . 'function getResultats() { ' . " \n" ;
			$txt .= " \t \t " . 'return $this->resultats ' . " \n";
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;
	}
	
	
	function faitSetLimite() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction mutatrice de la limite' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @param string limite' . "\n";
		$txt .= " \t" . '*/'. "\n";
		
		$txt .= " \t " . 'function setLimite( $limite ) { ' . " \n" ;
			$txt .= " \t \t " . '$this->limite =  $limite; ' . " \n";
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;
	}
	
	
	// ajouté par Yann ( code de Charles )
	function faitGetInfo() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction de recherche de données' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '* @param string champs'  . "\n";
		$txt .= " \t" . '*/' . "\n";
		
		/* création de la fonction */
		$txt .= " \t" . ' function getInfos( $champs = "*" ) {' . "\n ";
	 		$txt .= " \t\t" . '$variables = array( ';
			for( $i = 0; $i < count( $this->champs ); $i++ ) {
				$txt .= "'" . $this->champs[ $i ][ 'champ' ];
				if( count( $this->champs ) -1 != $i ) {
					$txt .= "',";
				}
				else {
					$txt .= "'";
				}
	 		}
			$txt .= "); \n ";
			$txt .= " \t\t" . ' $trouve = false; ' . "\n";
	 		$txt .= " \t\t " . '$recherche = \' 1 = 1 \'; ' . "\n";
			$txt .= " \t\t " . '$operateurDebut = " = \'"; ' . "\n";
			$txt .= " \t\t " . '$operateurFin = "\'"; ' . "\n";
			
			$txt .= " \t\t " . 'if( !$this->rechercheExact ) { ' . " \n ";
				$txt .= " \t\t\t " . '$operateurDebut = " LIKE \'%";' . " \n ";
				$txt .= " \t\t\t " . '$operateurFin = "%\'";' . " \n ";
			$txt .= " \t\t " . '} ' . " \n ";
	  		$txt .= " \t\t" . ' for ( $i = 0; $i < count( $variables ); $i++ ) { ' . "\n";
				$txt .= " \t\t\t" . 'if ( !empty( $this->$variables[ $i ] ) ) {  ' . "\n";
				$txt .= " \t\t\t\t" . ' $trouve = true; ' . "\n";
				$txt .= " \t\t\t\t /* Ajout de l'opérateur */ \n ";
				$txt .= " \t\t\t\t" . ' if ( !empty( $recherche ) ) { ' . "\n";
					$txt .= " \t\t\t\t\t" . ' $recherche .= " AND "; ' . "\n";		
				$txt .= " \t\t\t\t } \n ";
				$txt .= " \t\t\t\t" . ' $variable = $variables[ $i ];' . "\n";	
				$txt .= " \t\t\t\t" . ' $tableau = $this->$variable;' . "\n";	
				$txt .= " \t\t\t\t" . ' $valeur = $tableau[ 0 ];' . "\n";	
				$txt .= " \t\t\t\t /* Concaténation des critères de recherche */ \n ";
				$txt .= " \t\t\t\t" . ' if ( is_numeric( $valeur ) ) { ' . "\n";
					$txt .= " \t\t\t\t\t" . ' $recherche .= "' . $this->table . '" . $variables[ $i ] . " = " . $valeur. " "; ' . "\n";
				$txt .= " \t\t\t\t " . '} else { ' . "\n";
					$txt .= " \t\t\t\t\t" . ' $recherche .= "' . $this->table . '" . $variables[ $i ] . $operateurDebut . addslashes( $valeur ) . $operateurFin; ' . "\n";
				$txt .= " \t\t\t\t } \n ";
	   		$txt .= " \t\t\t } \n ";		
			$txt .= " \t\t } \n ";
			$txt .= " \t\t " . '$infos = $this->oBd->query( "SELECT " . $champs . " FROM ' . $this->table . ' WHERE " . $recherche . $this->ordre . $this->limite ); ' . "\n";
			$txt .= " \t\t " . '$this->resultats = $infos;' . "\n";
			$txt .= " \t\t " . '$this->cleanup();' . "\n";
	  		
			// faire en sorte qu'il met les résultats dans les variables de la classes en tableau
			$txt .= " \t\t" . ' for ( $i = 0; $i < count( $infos ); $i++ ) { ' . "\n"; 
				for( $i = 0; $i < count( $this->champs ); $i++ ) {
					$txt .= "\t \t \t" . '$this->' . $this->champs[ $i ][ 'champ' ] . ' = $infos[ $i ][ \'' . $this->champs[ $i ][ 'champ' ] . '\'] ;' . " \n";
				} 
			$txt .= " \t\t } \n ";		
		$txt .= " \t} \n ";
		return $txt;
	}
	
	function faitCleanup() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Fonction remet les variables membres à zéro' . "\n";
		$txt .= " \t" . '* @access private' . "\n";
		$txt .= " \t" . '*/' . "\n"; 
		
		$txt .= " \t function cleanup() { \n" ;
		for( $i = 0; $i < count( $this->champs ); $i++ ) {
			$txt .= " \t \t" . '$this->' . $this->champs[ $i ][ 'champ' ] . ' = array();' . " \n ";
		} 
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;	
	}
	
	
	function faitRechercheExact() {
		/* Ajout des commentaires de la fonction */
		$txt = " \t" . '/**' . "\n";
		$txt .= " \t" . '* @desc Indique si la recherche dois etre exact ou pas ( true = LIKE \'%x%\' )" ),' . "\n";
		$txt .= " \t" . '* @access public' . "\n";
		$txt .= " \t" . '*/' . "\n";
		
		$txt .= " \t " . 'function setRechercheExact( $b ) { ' . " \n" ;
			$txt .= " \t \t " . '$this->rechercheExact =  $b; ' . " \n";
		$txt .= " \t " . '} '  . " \n \n  "; 
		return $txt;
	}
	
	/**
	 * Fonction qui affiche un message d'erreur critique
	 * @param $message String
	 */
	function _erreur( $message ) {
		die( "<h1>" . $message . "</h1>" );
	}
}